import utils from '../../utils/utils'
let demo = () => {
    //### 001. js类型判断
    //```
    function typeJs(demo) {
        let outString = Object.prototype.toString.call(demo);
        let beginIndex = outString.indexOf(' ');
        let endIndex = outString.indexOf(']');
        // console.log(outString.slice(beginIndex, endIndex));
    }
    typeJs(222222222222)

    // console.log(Object.prototype.toString.call("jerry")); //[object String]
    // console.log(Object.prototype.toString.call(12)); //[object Number]
    // console.log(Object.prototype.toString.call(true)); //[object Boolean]
    // console.log(Object.prototype.toString.call(undefined)); //[object Undefined]
    // console.log(Object.prototype.toString.call(null)); //[object Null]
    console.log(Object.prototype.toString.call({
        name: "jerry"
    })); //[object Object]
    // console.log(Object.prototype.toString.call(function() {})); //[object Function]
    // console.log(Object.prototype.toString.call([])); //[object Array]
    // console.log(Object.prototype.toString.call(new Date)); //[object Date]
    // console.log(Object.prototype.toString.call(/\d/)); //[object RegExp]
    //```

    //### 002. 字符串截取
    //```
    //slice 方法可通过指定的开始和结束位置，提取字符串的某个部分，并以新的字符串返回被提取的部分。语法如下：
    //substring 方法用于提取字符串中介于两个指定下标之间的字符。语法如下：
    //substr 方法用于返回一个从指定位置开始的指定长度的子字符串。语法如下：
    //```

    //### 003. for of技巧
    //```
    //map 返回的item是给数组。
    let a3 = new Map();
    a3.set('name', 'he').set('age', '23');
    for (let [key, value] of a3) {
        // console.log(key, value);
    }
    //```

    //### 004. webpack 批量导入图片
    //```
    let requireContext = require.context('./img', false); //路径 是否子目录 文件后缀
    let images = requireContext.keys().map(requireContext);
    // console.log(images); //返回图片数组
    //```

    //### 005. 瀑布流思路
    //```
    // let requireContext=(require as any).context('./img', false);//路径 是否子目录 文件后缀
    // let images = requireContext.keys().map(requireContext);
    // // console.log(requireContext)

    // let nowWidth = null;//当前图片的宽度  
    // let nowHeight = null;//当前图片的宽度
    // let cols = 4;//列数
    // let heightArr:number[] =[];//存放每列的当前高度
    // //得到图片开始计算高度
    // images.forEach((item:any,index:any) => {
    //   nowWidth = ($('.imgs div').eq(index) as any).width();//当前图片的宽度  
    //   nowHeight = ($('.imgs div').eq(index) as any).height();//当前图片的宽度
    //   if(index<cols){
    //     heightArr[index]=nowHeight;
    //   }else{
    //     //因为是循环,排完第一排 就第二排。heightArr每列的高度都在不断累加
    //     var minHeight =Math.min(...heightArr);
    //     //根据当前最小的高度 判断是第几列
    //     var minCol = $.inArray(minHeight,heightArr);
    //     //设置样式
    //     $('.imgs li').eq(index).css({
    //       position:'absolute',
    //       left: minCol*nowWidth +'px',
    //       top: minHeight+'px'
    //     })
    //     //高度累加
    //     heightArr[minCol] += nowHeight;
    //   }
    // });
    //```

    //### 005. 实现一个indexOf效果
    //```
    (function() {
        function myIndexOf(str) {
            let strLength = str.length;
            let stringLength = this.length;
            if (strLength > stringLength) return -1;
            //利用循环截取目标字符串
            for (let ii = 0; ii < stringLength.length - strLength + 1; ii++) {
                if (str === this.substr(ii, strLength)) {
                    // console.log(ii);
                    return ii;
                }
            }
        }
        String.prototype.myIndexOf = myIndexOf;
    })()
    String('12345').myIndexOf('23')
    //```

    //### 006. 原型
    //```
    // 构造函数是一种特殊的方法，主要用来在创建对象时初始化对象。每个构造函数都有prototype(原型)(箭头函数以及Function.prototype.bind()没有)属性，
    // 这个prototype(原型)属性是一个指针，指向一个对象，这个对象的用途是包含特定类型的所有实例共享的
    // 属性和方法，即这个原型对象是用来给实例对象共享属性和方法的。每个实例对象的__proto__都指向这个
    // 构造函数/类的prototype属性。
    //```

    //### 007. new的实现过程
    //```
    //构造函数 参数
    function _new(Fn, ...arg) {
        let obj = {};
        //这个对象的__proto__指向构造原型
        obj.__proto__ = Fn.prototype;
        //构造函数的this 要是obj
        Fn.call(obj, ...arg);
        //最后肯定要返回个实例
        return obj;
    }
    //```

    //### 008. 行内元素的特点？
    //```
    //1，行内元素如果不定位，会从左往右放在一排。
    //2，宽高就是内容宽高、设置宽高无效
    //```

    //### 008. 如何实现一个 call 函数
    //```
    Function.prototype.myCall = function(context) {
            var context = context || window
                // 给 context 添加一个属性
                // getValue.call(a, 'yck', '24') => a.fn = getValue
            context.fn = this
                // 将 context 后面的参数取出来
            var args = [...arguments].slice(1)
                // getValue.call(a, 'yck', '24') => a.fn('yck', '24')
            var result = context.fn(...args)
                // 删除 fn
            delete context.fn
            return result
        }
        //```

    //### 009. 如何实现排序二叉数
    //```
    function TwoTree() {
        //节点函数
        var Node = function(key) {
                this.key = key;
                this.left = null;
                this.right = null;
            }
            //根节点
        var root = null;
        //插入节点函数
        this.insert = function(key) {
                var newNode = new Node(key);
                //如果没有根节点 第一次调用的就是根
                if (root === null) {
                    root = newNode;
                } else {
                    insertNode(root, newNode);
                }
            }
            //插入一个新节点
        var insertNode = function(node, newNode) {
                if (newNode.key < node.key) {
                    if (node.left === null) {
                        node.left = newNode;
                    } else {
                        insertNode(node.left, newNode);
                    }
                } else {
                    if (node.right === null) {
                        node.right = newNode;
                    } else {
                        insertNode(node.right, newNode);
                    }
                }
            }
            //添加中序排列
        this.inOrderTraverse = function(callback) {
                //传入根节点 便利所有节点 升序排列
                inOrderTraverseNode(root, callback);
            }
            //中序排列具体实现(访问节点)
        var inOrderTraverseNode = function(node, callback) {
            if (node !== null) {
                inOrderTraverseNode(node.left, callback);
                callback(node.key);
                inOrderTraverseNode(node.right, callback);
            }
        }
        setTimeout(() => {
            // console.log(root);
        }, 2000);
    }
    //要插入的节点值
    var nodes = [8, 3, 10, 1, 6, 14, 4, 7, 13];
    //二叉树实例
    var twoTreeObj = new TwoTree();
    nodes.forEach(function(key) {
            twoTreeObj.insert(key);
        })
        //中序排列
    var callback = function(key) {
        // console.log(key);
    }
    twoTreeObj.inOrderTraverse(callback);
    //```

    // 面试总结
    // 1.react父组件更新，子组件会更新吗？
    // 2.如何防止子组件的无用渲染？
    // 3，(shouldComponentDidMount)怎么进行性能优化。
    // 4，useMemo如何进行优化 怎么做的？
    // 5，hooks组件和class组件的优缺点对比。
    // 6，两个不同网页之间能否不通过网络请求，进行数据交互。办法是什么？
    // 7，pc端和移动端像素不同，如何兼容？
    // 8，在移动端如何实现一个可以缩放的正方形盒子？
    // 9，useRef是干嘛的？如何使用。它和函数组件配合的时候怎么用？
    // 10，useEffect和useLayoutEffect的区别。
    // 11，context.provider如何进行使用？
    // 12，ts的inter是什么？
    // 13，webpack你除了用来基本的压缩，该做了什么？
    // 14，forEach能否被return？break呢？
    // 15，webpack如何配置链接的跳转。
    // 16，http域名能否访问https下的资源？如果可以？怎么做才可以？
    // 17，服务器状态吗304和405？
    // 18，css in module是什么？
    // 19，你更喜欢css in js还是css in module？
    // 20，css预编译语言是什么？
    // 21，解构赋值是什么？
    // 22，如何缓存网页。
    // 23，如何不缓存网页？
    // 24，浏览器存储。
    // 25，cookies会被跨域影响吗？ 
    // 26，个人职业规划？

    //### 010. 承诺对象+try
    //```
    // var pro = new Promise((reslove,reject)=>{
    //   reject(3333333333333)
    // })
    // pro.then((res)=>{
    //   try {
    //     // console.log(res);
    //     // console.log(res);
    //     // console.log(res);
    //     // console.log(res);
    //   } catch (error) {
    //     // console.log(error);
    //   }
    // }).catch((err)=>{
    //   // console.log(err)
    // })
    //```

    //### 011. 测试 async await
    //```
    //async函数返回的 Promise 对象，必须等到内部所有await命令后面的 Promise 对
    //象执行完，才会发生状态改变，除非遇到return语句或者抛出错误。也就是说，只有
    //async函数内部的异步操作执行完，才会执行then方法指定的回调函数。
    //正常情况下，await命令后面是一个 Promise 对象，返回该对象的结果。
    //如果不是 Promise 对象，就直接返回对应的值。
    // const demo = async ()=>{
    //   var aa = await  aaa();
    //   return aa
    // }
    // var aaa = ()=>{
    //   // console.log('111111111111111111111111')
    //   //return '1111111111111111112';
    // }
    // demo().then(result=>{
    //   // console.log('输出',result);
    // })
    //```
    //### 012. 块级作用域
    //```
    //块级作用域，使用let声明的变量只能在块级作用域里访问，有“暂时性死区”的特性（也就是说声明前不可用）
    //```

    //### 013. Object.create() 创建对象的好处，对象比较纯净，没有任何属性，能规避for in访问原型属性
    //```
    function a13() {
        this.name = 100;
    }

    function b13() {
        this.age = 333;
    }
    b13.prototype = new a13();
    var aa13 = new b13();
    for (var ii13 in aa13) {
        // console.log(ii13);
    }
    //```

    //### 014. 包装类 执行的时候生成一个包装类 然后马上销毁
    //``` 
    //为了便于操作基本类型，ECMAScript提供了三个特殊的引用类型：Boolean、Number和String。
    //实际上，每当读取一个基本类型的值时，后台就会创建一个对应的基本包装类型的对象,执行完**立即销毁**

    (function() {
        let a = '111';
        let b = new String();
        let r1 = a instanceof String;
        let r2 = b instanceof String;
        let r3 = typeof(a);
        // console.log(r1, r2, r3)
    })()
    //``` 

    //### 015. map()第二个参数是作为第一个回调函数的this,是一个对象;
    //``` 
    var aa15 = [2, 3, 4, 5, 6, 7];
    var bb15 = 33333;
    var aaa15 = aa15.map(function(item, index) {
        // console.log(this); // he
        return item = item + 1;
    }, bb15)
    // console.log(aa15)
    // console.log(aaa15)
        //``` 






    // ### 016.扩展运算符(...)
    //```
    //用于取出参数对象的所有可遍历属性，然后拷贝到当前对象之中。
    var aa16 = [1, 2, 3, 4];
    var bb16 = [10, 20, 30];
    // console.log([...aa16, ...bb16]);
    var cc16 = { name: 1, age: 3 };
    var dd16 = { ss: 2 };
    // console.log({...cc16, ...dd16 })
        //```

    // ### 017.js是静态作用域
    //```
    //个人理解：调用函数，输出结果看 函数声明的作用域的数据。
    //```

    // ### 018.js执行上下文
    //```
    // var scope = "global scope";
    // function checkscope(){
    //     var scope = "local scope";
    //     function f(){
    //         return scope;
    //     }
    //     return f();
    // }
    // checkscope();
    //模拟执行过程
    // ECStack.push(checkscope)
    // ECStack.push(f)
    // ECStack.del(f)
    // ECStack.del(checkscope)

    // var scope = "global scope";
    // function checkscope(){
    //     var scope = "local scope";
    //     function f(){
    //         return scope;
    //     }
    //     return f;
    // }
    // checkscope()();

    //```

    // ### 019.变量对象
    //```
    //变量对象是与执行上下文相关的数据作用域，存储了在上下文中定义的变量和函数声明。
    //就是 一个专门存变量和函数声明的东西 在作用域中。
    function aa19() {
        // console.log(bb); //fun bb
        var bb = 1111;

        function bb() {
            // console.log('bbbbbbbbbb')
        }

    }
    aa19();
    //```

    // ### 020.JS值传递理解
    //```
    // //理解为：所有传的参数都相当于一个副本（或者理解为赋值）基本函数就是值传递 对象就是指引传递
    // function aa20(data){
    //     data=20;
    //     console.log(data)
    //     //翻译为
    //     // var _data=data;
    //     // console.log(_data);
    // }
    // var data =1;

    // var obj = {
    // value: 1
    // };
    // function foo(o) {
    //     o.value = 2;
    //     console.log(o.value); //2
    // }
    // foo(obj);
    // console.log(obj.value) // 2
    //```

    // ### 021.React useEffect 第二个参数的理解
    //```
    //useEffect 毕竟包含了mountend updata 只要有更新就会触发，
    //第二个参数 每次调用时候都会判断里面的值是否改变，改变了就触发更新，空数组没值
    //始终不变，就只会触发一次
    // useEffect(() => {
    //     // 让resize事件触发handleResize
    //     window.addEventListener('resize', handleResize)
    //     return () => window.removeEventListener('resize', handleResize)
    //  }, [])
    //```

    // ### 022.js 遍历 循环 总结
    //```
    // //forEach
    // let aa20 = [2,3,4,5,6,7];
    // let bb20 = {name:222}
    // //forEach怎么说呢 带下标 比 for ii 语义化
    // aa20.forEach(function(item,index){
    //     console.log(this.name);
    //     item=item*2;
    // },bb20)
    // console.log(aa20)
    // //map 用于修改数据本身 返回一个新的数据
    // let cc20=aa20.map((item)=>{
    //     return item *10;
    // })
    // console.log(cc20);
    // //for of 数组
    // //for in 对象可枚举的属性
    // let dd20 =new Object({name:'何三磊',age:30});
    // console.log(Object.keys(dd20))
    // //filter 循环 后面跟个过滤函数 当结果为真 才返回，返回个新的数据
    // let ee20 = aa20.filter((item)=>{
    //     return item<6;
    // })
    // console.log(ee20);
    // //类似于  &
    // //every 循环 和filter 类似 参数是判断条件。如果为假，就不执行了。全部通过才为true
    // var ff20 = [ 1, 2, 3, 4, 5, 6 ]; 
    // console.log(ff20.every(function(item, i) {
    //     console.log(item,i)
    //     return item < 3;
    // }))
    // //类似于 |
    // //every 循环 和filter 类似 参数是判断条件。如果为真，就不执行了。有一个成立就为true
    // console.log(ff20.some(function(item, i) {
    //     console.log(item,i)
    //     return item< 3;
    // }))
    //```

    //实用代码封装
    // ### js 两数组合并 
    //```
    //以aa为基础 bb相同的项 替换aa的
    var aa = [{ 'F_SetDate': "201802" },
    { 'F_Name': "HHHH" },
    { 'F_SlaveNo': "001" },
    { 'F_TransFlowId': null },
    { 'F_UpdateBy': "System" },
    { 'F_UpdateDate': "2020-04-09 11:56:35" }];

    var bb = [{ 'F_SetDate': "10000" },
    { 'F_SlaveNo': "10000" },
    { 'F_TransFlowId': 10000 },
    { 'F_UpdateBy': "10000" },
    { 'F_UpdateDate': "10000" }]

    for(let ii =0;ii<aa.length;ii++){
        for(let jj =0;jj<bb.length;jj++){
            if(Object.keys(aa[ii])[0]===Object.keys(bb[jj])[0]){
                aa[ii]=bb[jj];
            }
        }
    }
    console.log(aa);
    //```

    // ### js 一个数组找到相同元素 累加值  
    //```
    let _cardDataArr = [];//金额累加后的数组 最后的数组
    let cardDataArr = [{ F_MasterNo: '001', F_SlaveNo: '001', F_TransAmount: 1000, F_Card: '001_001' },
        { F_MasterNo: '001', F_SlaveNo: '001', F_TransAmount: 1000, F_Card: '001_001' },
        { F_MasterNo: '001', F_SlaveNo: '002', F_TransAmount: 100, F_Card: '001_002' },
        { F_MasterNo: '001', F_SlaveNo: '002', F_TransAmount: 100, F_Card: '001_002' },
        { F_MasterNo: '001', F_SlaveNo: '003', F_TransAmount: 10, F_Card: '001_003' }]
    for (let jj = 0; jj < cardDataArr.length; jj++) {
        if (_cardDataArr.length > 0) {
            //判断当前卡是否在_cardDataArr
            let haveDataArr = _cardDataArr.filter((item) => item.F_Card == cardDataArr[jj].F_Card);
            if (haveDataArr.length > 0) {
                //循环 新的数组 找到相同的 累加金额
                _cardDataArr.forEach((item) => {
                    if (cardDataArr[jj].F_Card === item.F_Card) {
                        item.F_TransAmount += cardDataArr[jj].F_TransAmount;
                    }
                })
            } else {
                _cardDataArr.push(cardDataArr[jj])
            }
        } else {
            _cardDataArr.push(cardDataArr[jj]);
        }
    }
    console.log(_cardDataArr);
    //```

    // ### 024. 过时 闭包
    //```
    //个人理解 useEffect这个闭包 一直都在，这时 count = 0 ，不管你怎么变
    //里面的log函数一直调用的是useEffect的count 就一直输出0
    // function WatchCount() {
    //     const [count, setCount] = useState(0);
        
    //     useEffect(function() {
    //         setInterval(function log() {
    //         console.log(`Count is: ${count}`);
    //         }, 2000);
    //     }, []);
        
    //     return (
    //         <div>
    //         {count}
    //         <button onClick={() => setCount(count + 1) }>
    //             加1
    //         </button>
    //         </div>
    //     );
    // }
    //```

    //定时器
    // var setTime;
    // function queryStatus(_time){
    //   clearTimeout(setTime);
    //   setTime = setTimeout(() => {
    //     // console.log(_time);
    //     if(_time>10){
    //       return  true;
    //     }else{
    //       return  false;
    //     }
    //   }, _time*1000);
    // }
    // function successCallback(){
    //   // console.log('结束')
    // }
    // function omniPoller(queryStatus, successCallback) {
    //   // Implement your solution here
    //   let _time =1;
    //   var pro = new Promise((reslove,reject)=>{
    //     while(false){
    //       _time*=2;
    //       let out = queryStatus(_time);
    //       if(out){
    //         reslove(successCallback);
    //         return;
    //       }
    //     }
    //   })
    //   pro.then((res)=>{
    //     res();
    //   }).catch((err)=>{
    //     // console.log(err)
    //   })
    // }

    // omniPoller(queryStatus,successCallback)




    // function queryStatus() {
    //   let arr = [true, false, false, false,false, false, false,false, false, false];
    //   let randomNumber = parseInt(Math.random() * arr.length);
    //   return arr[randomNumber];
    // }

    // function successCallback() {
    //   // console.log('Callback');
    // }
    // let m = 1000;

    // function omniPoller(queryStatus, successCallback) {
    //   setTimeout(async () => {
    //     let flag = await queryStatus();
    //     if (flag) {
    //       successCallback();
    //       return;
    //     }
    //     // console.log(m);
    //     m *= 1.5;
    //     // 递归            
    //     omniPoller(queryStatus, successCallback);
    //   }, m);
    // }
    // omniPoller(queryStatus, successCallback);

    // # 重学前端，我只说干货
    // ### 001.防抖节流
    // ```
    //形成一个闭包环境
    const debounce = (func, delay) => {
        let timer;
        return function (...args) {
            if(timer) {
                clearTimeout(timer);
            }
            timer = setTimeout(() => {
                func.apply(this, args);
                clearTimeout(timer);
            }, delay);
        };
    };
    let  fun001 = () => {
        console.log(new Date());
    }
    let out = debounce(fun001,1000);//返回一个函数本体
    //每次执行理解为，在debounce环境的 执行函数，类似全局声明了timer,判断是否设置了定时器，这样不会污染环境
    //怎么感觉每次 return 函数都是为了利用闭包 不污染环境
    out();

    //节流 不管你怎么疯狂点 定时执行一次
    function throttle(fn,delay){
        let valid = true
        return function() {
            //上一次执行都设置false 重复调用 都会走这里
            if(!valid){
                return false 
            }
            // 工作时间，执行函数并且在间隔期内把状态位设为无效
                valid = false
                setTimeout(() => {
                    fn()
                    valid = true;
                }, delay)
        }
    }
    let out1 =throttle(fun001,1000);
    out1()
    // ```  

    // ### 002.判断是否是对象
    // ```
    function isObject(value) {
        return value === Object(value);
    }
    
    isObject([]) // true
    isObject(true) // false
    // ```

    // ### 003.filter
    // ```
    // filter方法用于过滤数组成员，满足条件的成员组成一个新数组返回。
    // 它的参数是一个函数，所有数组成员依次执行该函数，
    // 返回结果为true的成员组成一个新数组返回。该方法不会改变原数组。
    // ```

    // ### 004.some()，every()
    // ```
    //some 只要有符合条件就返回ture
    var arr = [1, 2, 3, 4, 5];
        arr.some(function (elem, index, arr) {
        return elem >= 3;
    });
    //every 必须每个都满足才true
    var arr = [1, 2, 3, 4, 5];
    arr.every(function (elem, index, arr) {
        return elem >= 3;
    });
    // ```
}
export default demo;